import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { ElMessage } from 'element-plus'
import { loginApi, logoutApi, getUserInfoApi } from '@/api/auth'
import { getRoleList, getUserRoleList } from '@/api/system'
import type { LoginPayload } from '@/types/auth'
import type { User } from '@/types/system'

const TOKEN_KEY = 'myth_token'
const TOKEN_TYPE_KEY = 'myth_token_type'

export const useUserStore = defineStore('user', () => {
  const token = ref<string>(localStorage.getItem(TOKEN_KEY) || '')
  const tokenType = ref<string>(localStorage.getItem(TOKEN_TYPE_KEY) || 'Bearer')
  const user = ref<User | null>(null)
  const roles = ref<string[]>([])
  const permissions = ref<string[]>([])
  const initialized = ref(false)
  const loadingProfile = ref(false)

  const isAuthenticated = computed(() => !!token.value)
  const displayName = computed(() => user.value?.real_name || user.value?.username || '用户')

  const setToken = (value: string, type = 'Bearer') => {
    token.value = value
    tokenType.value = type || 'Bearer'
    if (value) {
      localStorage.setItem(TOKEN_KEY, value)
      localStorage.setItem(TOKEN_TYPE_KEY, tokenType.value)
    } else {
      localStorage.removeItem(TOKEN_KEY)
      localStorage.removeItem(TOKEN_TYPE_KEY)
    }
  }

  const hydrateRolesFromAssignments = async (userId: number) => {
    const [roleResult, assignmentResult] = await Promise.all([
      getRoleList({ limit: 500 }),
      getUserRoleList({ limit: 2000 })
    ])
    const roleMap = new Map(roleResult.items.map((role: any) => [role.id, role.role_code]))
    const assignedCodes = assignmentResult.items
      .filter((item: any) => item.user_id === userId)
      .map((item: any) => roleMap.get(item.role_id))
      .filter((code: any): code is string => Boolean(code))

    roles.value = assignedCodes.length ? assignedCodes : []
  }

  const fetchProfile = async () => {
    if (!token.value) return
    try {
      loadingProfile.value = true
      const data = await getUserInfoApi()
      user.value = data.user
      permissions.value = data.permissions || []
      if (data.roles && data.roles.length) {
        roles.value = data.roles
      } else if (data.user?.id) {
        await hydrateRolesFromAssignments(data.user.id)
      }
    } finally {
      loadingProfile.value = false
    }
  }

  const login = async (payload: LoginPayload) => {
    const data = await loginApi(payload)
    setToken(data.access_token, data.token_type)
    user.value = data.user
    try {
      await fetchProfile()
    } catch (error) {
      console.error('fetch profile after login failed', error)
    }
    initialized.value = true
    ElMessage.success('登录成功')
  }

  const logout = async () => {
    try {
      await logoutApi()
    } catch (error) {
      console.error('logout failed', error)
    } finally {
      forceLogout()
    }
  }

  const initAuth = async () => {
    if (initialized.value) return
    if (token.value) {
      try {
        await fetchProfile()
      } catch (error) {
        console.error('init auth failed', error)
        forceLogout()
      }
    }
    initialized.value = true
  }

  const forceLogout = () => {
    setToken('')
    user.value = null
    roles.value = []
    permissions.value = []
    initialized.value = false
  }

  const hasRole = (role: string) => roles.value.includes(role)
  const hasSomeRole = (targetRoles: string[]) =>
    !targetRoles.length || targetRoles.some((role) => roles.value.includes(role))

  return {
    token,
    tokenType,
    user,
    roles,
    permissions,
    initialized,
    loadingProfile,
    isAuthenticated,
    displayName,
    login,
    logout,
    initAuth,
    fetchProfile,
    forceLogout,
    hasRole,
    hasSomeRole
  }
})
